package com.ruoyi.web.controller.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.framework.config.ServerConfig;
import com.ruoyi.web.controller.domain.EnterpriseInfo;
import com.ruoyi.web.controller.domain.ExcelImportInfo;
import com.ruoyi.web.controller.mapper.ExcelImportInfoMapper;
import com.ruoyi.web.controller.vo.ExcelQuery;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class ExcelImportInfoServiceImpl extends ServiceImpl<ExcelImportInfoMapper, ExcelImportInfo> implements IExcelImportInfoService {

    @Resource
    private EnterpriseInfoServiceImpl enterpriseInfoServiceImpl;
    @Resource
    private IShortLinkService shortLinkServiceImpl;

    @Resource
    private ServerConfig serverConfig;

    // 单次缓存的数据量
    public static final int BATCH_COUNT = 900;
    // 临时存储
    private List<EnterpriseInfo> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    // 每次任务执行完后等待60秒再执行下一次
    @Scheduled(fixedDelay = 30000)
    public void performTask() {
        LambdaQueryWrapper<ExcelImportInfo> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(ExcelImportInfo::getId, ExcelImportInfo::getFilePath)
                .isNull(ExcelImportInfo::getImportEndTime)
                .orderByAsc(ExcelImportInfo::getImportStartTime)
                .last("LIMIT 1");
        ExcelImportInfo one = getOne(queryWrapper);
        if (null == one) {
            return;
        }

        // Initialize short links
        final List[] shortLinks = new List[]{shortLinkServiceImpl.getList()};
        final int[] shortLinkIndex = {0}; // Track the current index of the short link

        // Set import start time
        one.setImportStartTime(LocalDateTime.now());
        Long id = one.getId();
        String fileUrl = getFileUrl(one);
        final Integer[] successCount = {0};
        final Integer[] failureCount = {0};
        final String[] error = {""};

        EasyExcel.read(fileUrl, EnterpriseInfo.class, new ReadListener<EnterpriseInfo>() {
            @Override
            public void invoke(EnterpriseInfo data, AnalysisContext context) {
                data.setFileId(id);
                data.setSource("导入");
                if (shortLinkIndex[0] >= shortLinks[0].size()) {
                    shortLinks[0] = shortLinkServiceImpl.getList();
                    shortLinkIndex[0] = 0;
                }
                data.setShortLink((String) shortLinks[0].get(shortLinkIndex[0]));
                shortLinkIndex[0]++;
                cachedDataList.add(data);
                if (cachedDataList.size() >= BATCH_COUNT) {
                    saveData();
                    cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                saveData();
            }

            // Save data
            private void saveData() {
                try {
                    enterpriseInfoServiceImpl.saveBatch(cachedDataList);
                    successCount[0] += cachedDataList.size();
                } catch (Exception e) {
                    failureCount[0] += cachedDataList.size(); // Record all failures if batch save fails
                    if (StringUtils.isEmpty(error[0])) {
                        error[0] = e.getMessage();
                    }
                }
            }
        }).sheet().doRead();

        String successCountStr = String.valueOf(successCount[0]);
        String failureCountStr = String.valueOf(failureCount[0]);

        // Set import end time
        one.setImportEndTime(LocalDateTime.now());
        one.setSuccessCount(successCountStr);
        one.setFailureCount(failureCountStr);
        one.setRemarks(error[0]);
        one.setTotalCount(String.valueOf(successCount[0] + failureCount[0]));
        updateById(one);
    }

    private static String getFileUrl(ExcelImportInfo one) {
        String path = one.getFilePath();
        path = getUploadPath(path);
        String uploadPath = RuoYiConfig.getUploadPath();
        return uploadPath + "/" + path;
    }


    @Override
    public void uploadFile(MultipartFile file) {
        String filePath = RuoYiConfig.getUploadPath();
        String fileName;
        try {
            fileName = FileUploadUtils.upload(filePath, file);
        } catch (IOException e) {
            log.error("文件上传失败！失败原因：{}", e.getMessage());
            throw new ServiceException("文件上传失败！");
        }
        ExcelImportInfo info = new ExcelImportInfo();
        info.setOriginalFilename(file.getOriginalFilename());
        info.setNewFilename(FileUtils.getName(fileName));
        info.setImportStartTime(LocalDateTime.now());
        info.setFilePath(serverConfig.getUrl() + fileName);
        info.setTotalCount("-");
        info.setSuccessCount("-");
        info.setFailureCount("-");
        save(info);
    }

    @Override
    public void download(Long id, HttpServletResponse response) {
        if (null == id) {
            throw new ServiceException("未获取到相关数据！");
        }
        ExcelImportInfo info = getById(id);
        String string = getFileUrl(info);
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        try {
            FileUtils.setAttachmentResponseHeader(response, info.getOriginalFilename());
            FileUtils.writeBytes(string, response.getOutputStream());
        } catch (IOException e) {
            log.error("文件下载失败，失败原因{}", e.getMessage());
            throw new ServiceException("文件下载失败！");
        }
    }

    @Override
    public TableDataInfo queryList(ExcelQuery query) {
        Page<ExcelImportInfo> page = new Page<>(query.getPageNum(), query.getPageSize());
        LambdaQueryWrapper<ExcelImportInfo> queryWrapper = Wrappers.lambdaQuery();
        // 文件名模糊查询
        queryWrapper.like(StringUtils.isNotEmpty(query.getOriginalFilename()),
                ExcelImportInfo::getOriginalFilename, query.getOriginalFilename());
        // 导入开始时间和结束时间的范围查询
        queryWrapper.ge(query.getImportStartTime() != null,
                        ExcelImportInfo::getImportStartTime, query.getImportStartTime())
                .le(query.getImportEndTime() != null,
                        ExcelImportInfo::getImportEndTime, query.getImportEndTime());
        // 备注模糊查询
        queryWrapper.like(StringUtils.isNotEmpty(query.getRemarks()),
                ExcelImportInfo::getRemarks, query.getRemarks());
        List<ExcelImportInfo> list = list(page, queryWrapper);
        return new TableDataInfo(list, (int) page.getTotal());
    }

    @Override
    public void delete(Long id) {
        boolean b = removeById(id);
        if (!b) {
            throw new ServiceException("删除失败，请重试！");
        }
        UpdateWrapper<EnterpriseInfo> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("file_id", id).set("deleted", true);
        enterpriseInfoServiceImpl.update(updateWrapper);
    }

    public static String getUploadPath(String url) {
        int index = url.indexOf("/upload/");
        if (index != -1) {
            return url.substring(index + "/upload/".length());
        }
        return "";
    }
}
